package cz.czu.pef.DataModelling;

import java.util.*;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cz.czu.pef.DataModelling.utils.Lazy;

/**
 * This entity represents type of roles which employee can have in companies he/she works in.
 * Examples: CEO, Manager, Team Leader, etc.
 * 
 * @author rstribrn
 *
 */
@Entity
@Table(name="ROLE_TYPES")
@NamedQueries({
	@NamedQuery(name="findRoleTypeByCode", query="SELECT rt FROM RoleType rt WHERE rt.code = :code")
})
@ManagedBean(name="roleType")
@ViewScoped
@Component
@Scope(value="prototype")
public class RoleType extends CommonPersistenceObject
{
	private static final long serialVersionUID = -1890176039634399662L;

	/*
	 * Entity attributes (some inherited).
	 */

	/*
	 * Relations
	 */
	/**
	 * Relation to Role instances created with this RoleType
	 */
	@OneToMany(fetch=FetchType.LAZY, targetEntity=Role.class, mappedBy="roleType") // no cascade!
	//@OnDelete(action=OnDeleteAction.NO_ACTION)
	private Set<Role> roles;

	/**
	 * Required medical examination which person must pass in order to fulfill this RoleType's requirements
	 */
	@ManyToMany(fetch=FetchType.LAZY, targetEntity=MedicalExaminationTypeForRoleType.class, cascade={CascadeType.ALL})
	@JoinTable(name="MAP_RT__MET_2")
	private Set<MedicalExaminationTypeForRoleType> medExamTypesForRoleTypes;

	/**
	 * Required trainings which person must pass in order to fulfill this RoleType's requirements
	 */
	@ManyToMany(fetch=FetchType.LAZY, targetEntity=TrainingTypeForRoleType.class, cascade={CascadeType.ALL})
	@JoinTable(name="MAP_RT__TT_FRT")
	private Set<TrainingTypeForRoleType> traningTypesForRoleTypes;


	protected RoleType()
	{
		super(null, null, null);
	}

	public RoleType(String roleCode, String roleName, String roleDescription)
	{
		super(roleCode, roleName, roleDescription);
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<Role> getRoles()
	{
		return roles;
	}
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<Role> getRolesAsList()
	{
		return new ArrayList<Role>(getRoles());
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<MedicalExaminationTypeForRoleType> getMedicalExaminationTypeForRoleType()
	{
		return medExamTypesForRoleTypes;
	}
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<MedicalExaminationTypeForRoleType> getMedicalExaminationTypeForRoleTypeAsList()
	{
		return new ArrayList<MedicalExaminationTypeForRoleType>(getMedicalExaminationTypeForRoleType());
	}

	public void addMedicalExaminationTypeForRoleType(MedicalExaminationTypeForRoleType medicalExaminationTypeForRoleType)
	{
		if (this.medExamTypesForRoleTypes == null)
			this.medExamTypesForRoleTypes = new HashSet<MedicalExaminationTypeForRoleType>();
		this.medExamTypesForRoleTypes.add(medicalExaminationTypeForRoleType);
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<TrainingTypeForRoleType> getTraningTypesForRoleTypes()
	{
		return traningTypesForRoleTypes;
	}
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<TrainingTypeForRoleType> getTraningTypesForRoleTypesAsList()
	{
		return new ArrayList<TrainingTypeForRoleType>(getTraningTypesForRoleTypes());
	}

	public void addTrainingTypeForRoleType(TrainingTypeForRoleType traningTypesForRoleType)
	{
		if (this.traningTypesForRoleTypes == null)
			this.traningTypesForRoleTypes = new HashSet<TrainingTypeForRoleType>();
		this.traningTypesForRoleTypes.add(traningTypesForRoleType);
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
		builder.append("RoleType [toString()=");
		builder.append(super.toString());
		builder.append("]");
		return builder.toString();
	}

	/**
	 * Can be deleted after no role instances is referencing it.
	 */
	@Override
	public boolean canBeRemoved()
	{
		return getRoles().size() == 0;
	}
}
